import promidi.*;
import processing.serial.*;

MidiIO midiIO;
MidiOut midiOut;

Serial myPort;  // The serial port:
String preferredMidiOutput = "Out To MIDI Yoke:  5";

int controllerValue = 0;

int xMin = 50;    //constrain it onto screen
int xMax = 500;

int xPos=50;
int yPos=100;

int dir=0;

int currentControllerType = 102;

//Controller Types
final static int ctrlROTARYTYPE1 = 100;
final static int ctrlROTARYTYPE2 = 101;
final static int ctrlOPENHIGH = 102;
final static int ctrlOPENLOW = 103;
final static int ctrlCLOSED = 104;
final static int ctrlNOTES = 105;

//cc and shit
int ccValue = 20;
int stepSize = 5;
int noteValue = 42;

char inByte;

void setup() {
  // List all the available serial ports:
  size(600,200);
  stroke(255);
  rectMode(CENTER);
  frameRate(30);
  println(Serial.list());
  myPort = new Serial(this, Serial.list()[1], 9600);
  initializeMidi();
}

//all we have to do in the main loop is reference the 
//global variable x, which gets updated by the serialEvent
//autonomously

void draw() {    
  
  background(110);
  rect(xPos, yPos, 50, 50);    
}
// an event that gets called automatically every time there
// is a byte available in the serial port
void serialEvent(Serial port) {
  
  char inByte = myPort.readChar();
    
  if(inByte == '>'){
    xPos=constrain(xPos+1,xMin,xMax);
	dir=1;
	processMidiSpin(dir, currentControllerType); 
  }else if (inByte == '<'){
    xPos=constrain(xPos-1,xMin,xMax);
    dir=-1;
	processMidiSpin(dir, currentControllerType); 
  }else if (inByte == char(200)){
    processMidiTouch(-1);
  }else if (inByte == char(201)){
    processMidiTouch(1);
  }
}

void processMidiTouch(int state)
{
  if (state==1) {
    midiOut.sendNote(new Note(64,127,20));
  } else if (state==-1) {
    midiOut.sendNote(new Note(63,127,20));
  }
}

void processMidiSpin(int mDir, int controllerType)
{
   /*  controllerValue = constrain(controllerValue+mDir, 0, 127);
      midiOut.sendController(
        new Controller(20,controllerValue)
      );*/
	switch (controllerType) {
	
    case ctrlROTARYTYPE1:
        if (mDir < 0)
      midiOut.sendController(
        new Controller(ccValue,63)
      );
    else if (mDir > 0)
      midiOut.sendController(
        new Controller(ccValue,65)
      );
      break;
      // break is optional
	  
	  
    case ctrlROTARYTYPE2:
         if (mDir < 0)
      midiOut.sendController(
        new Controller(ccValue,127)
      );
    else if (mDir > 0)
      midiOut.sendController(
        new Controller(ccValue,1)
		);
      break;
	  
	  
	case ctrlOPENHIGH:
	if (mDir < 0)
	  controllerValue = constrain(controllerValue+mDir*stepSize, 0, 127);
	  else
      controllerValue = (controllerValue+mDir*stepSize)%127;
      midiOut.sendController(
        new Controller(ccValue,controllerValue)
		);
      break;
	  
	  
	case ctrlOPENLOW:
      if (mDir > 0)
	  controllerValue = constrain(controllerValue+mDir*stepSize, 0, 127);
	  else
      controllerValue = (controllerValue+mDir*stepSize)%127;
      midiOut.sendController(
        new Controller(ccValue,controllerValue)
		);
      break;
	case ctrlCLOSED:
      controllerValue = constrain(controllerValue+mDir*stepSize, 0, 127);
      midiOut.sendController(
        new Controller(ccValue,controllerValue)
		);
      break;
	  
	  
	case ctrlNOTES:
      midiOut.sendNote(new Note(noteValue+mDir,100,20)); 
      break;
    default: 
      // if nothing else matches, do the default
      // default is optional
  }

 
 
    
    //
}

void initializeMidi()
{
   //get an instance of MidiIO
  midiIO = MidiIO.getInstance(this);
  
  //print a list with all available devices
  midiIO.printDevices();
  
  midiOut = midiIO.getMidiOut(1, preferredMidiOutput);
}

